
#include "Ad9171.h"
#include "Spi.h"
#include "commHeader.h"
#include "ad9171Registers.h"
#include "Jesd204b.h"
#include "Jesd204c.h"
#include "Mem.h"
#include "Gpio.h"
#include <unistd.h>
#include "Lmx2820.h"
#include "Hmc7044.h"

static int ad9171Fd = -1;

int ad9171WrRd(uint32_t regAddress)
{
	if(ad9171Fd < 0) return -1;

    static unsigned char rbuf[10];
	static unsigned char tbuf[3];
	int wlen = 3,rlen = 1;
	tbuf[0] = (regAddress>>16)&0xff;
	tbuf[1] = (regAddress>>8)&0xff;
	tbuf[2] = regAddress&0xff;
	if(tbuf[0] >= 0x80) {
		wlen = 2;rlen = 1;
	} else {
		wlen = 3;rlen = 0;
	}
    if(spiTransmit(ad9171Fd,tbuf,wlen,rbuf,rlen) < 0){
		qlog_e("Ad9171 reg:%#x spi transmit failed..",regAddress);
        return -1;
    }

    return rbuf[0];
}

bool ad9171Open(const char* filename)
{
    ad9171Fd = spiInit(filename);
    if(ad9171Fd < 0){
        qlog_e("Open ad9171 failed!");
		return false;
    }
	return true;
}

void ad9171Close()
{
	close(ad9171Fd);
}

/**
 * @description: ad9171内部寄存器初始化函数 
 * @param  	: 无
 * @return 	: 无
 * @return {int*}
 */
static bool ad9171RegInit()
{
	uint8_t cnt = 0;
    uint8_t valueH,valueL,ad9171_pll_sts,
	ad9171_dll_sts,ad9171_serdes_pll_sts;

	for(cnt=0;cnt<6;cnt++){
		ad9171WrRd(ad9171_reset[cnt]);
		if(cnt == 4) {
			usleep(1200);
		}
	}
	valueH = ad9171WrRd(AD9171_ID_HIGH);
	valueL = ad9171WrRd(AD9171_ID_LOW);
	qlog_i("ad9171 ID = %#x%x", valueH,valueL);
	usleep(10000); //10ms

	//初始化AD9171
	for(cnt=0;cnt<3;cnt++) {
		ad9171WrRd(ad9171_cfg_clk[cnt]);
		if(cnt == 9) {
			usleep(10000);
		}
		if(cnt == 14) {
			usleep(10000);
		}
	}
	// ad9171_pll_sts		= ad9171WrRd(AD9171_PLL_STS);
	// while((ad9171_pll_sts & 0x00000001) == 0) {
	// 	// qlog_i("ad9171 pll unlock.");
	// 	usleep(10000);
	// 	ad9171_pll_sts	= ad9171WrRd(AD9171_PLL_STS);
	// } // confirm pll is locked


	for(cnt=0;cnt<8;cnt++) {
		ad9171WrRd(ad9171_cfg_dll[cnt]);
	}
	int m_lmxLock = 0,m_hmc7044Lock = 0;;
	ad9171_dll_sts		= ad9171WrRd(AD9171_DLL_STS);
	cnt = 0;
	while((ad9171_dll_sts & 0x00000001) == 0) {
		if(cnt++ % 100 == 0) {
			m_lmxLock = lmx2820GetLock();
            m_hmc7044Lock = hmc7044GetLock();
            qlog_w("等待LMX2820:%s,HMC7044:%s,时钟锁定..",
            (m_lmxLock == 2)?"锁定":"未锁定",
            (m_hmc7044Lock == 1)?"锁定":"未锁定");

			if(m_lmxLock != 2) {
				qlog_w("初始化流程,复位lmx2820设备..");
				if (lmx2820Reset()) {
					sleep(2);
					lmx2820Config();
				}
				sleep(2);
			}
			qlog_i("ad9171 dll unlock.");
			qlog_e("AD9171 初始化失败..");
			return false; //退出ad9171的初始化
		}
		
		usleep(10000);
		ad9171_dll_sts	= ad9171WrRd(AD9171_DLL_STS);
	} // confirm dll is locked


	for(cnt=0;cnt<5;cnt++) {
		ad9171WrRd(ad9171_cfg_calib[cnt]);
		if(cnt == 2) {
			usleep(10000);
		}
	}

	for(cnt=0;cnt<17;cnt++) {
		ad9171WrRd(ad9171_cfg_204b[cnt]);
	}

	for(cnt=0;cnt<25;cnt++) {
		ad9171WrRd(ad9171_cfg_channel_datapath[cnt]);
	}
	for(cnt=0;cnt<26;cnt++) {
		ad9171WrRd(ad9171_cfg_main_datapath[cnt]);
	}
	for(cnt=0;cnt<40;cnt++) {
		ad9171WrRd(ad9171_cfg_serdes[cnt]);
		if(cnt == 24) {
			sleep(1);
		}
	}
	ad9171_serdes_pll_sts		= ad9171WrRd(AD9171_SERDES_PLL_STS);
	while((ad9171_serdes_pll_sts & 0x00000001) == 0) {
		usleep(10000);
		ad9171_serdes_pll_sts	= ad9171WrRd(AD9171_SERDES_PLL_STS);
	} // confirm serdes pll is locked

	for(cnt=0;cnt<14;cnt++) {
		usleep(10000);
		ad9171WrRd(ad9171_cfg_204b_common[cnt]);
	}

	valueH = ad9171WrRd(AD9171_ID_HIGH);
	valueL = ad9171WrRd(AD9171_ID_LOW);
	qlog_i("ad9171 初始化完成..");
	qlog_i("ad9171 ID = %#X%X..", valueH,valueL);
	return true;
}

int ad9171Check()
{
	//检查链路是否建立成功
	uint32_t check_res;
	uint8_t ad9171_cgs	;
	uint8_t ad9171_frm	;
	uint8_t ad9171_chksum;
	uint8_t ad9171_ila	;
	ad9171_cgs				= ad9171WrRd(AD9171_CGS);		//SERDSES PLL is locked
	ad9171_frm				= ad9171WrRd(AD9171_FRM);		//FRAME_SYNC bit0-bit7
	ad9171_chksum			= ad9171WrRd(AD9171_CHKSUM);	//GOOD_CHECKSUM
	ad9171_ila				= ad9171WrRd(AD9171_ILA);		//INIT_LANE_SYNC
	check_res = ((uint32_t)ad9171_cgs<<24)|((uint32_t)ad9171_frm<<16)|((uint32_t)ad9171_chksum<<8)|ad9171_ila;
	return check_res;
}

static void jesd204bInit(void)
{
	//初始化JESD204B IP
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_8B10B_CFG,0x03021F03);//F:4; K:32
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_TX_ILA_CFG0,0x00);
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_SUB_CLASS,0x00000001);
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_TEST_MODE,0x00000000);
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_LANE_ENA,0x00000001);//L:1
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_TX_ILA_CFG1,0x000F0F01);//NP:16; N:16; M:2
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_TX_ILA_CFG2,0x00000000);
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_CTRL_SYSREF,0x00000002);
    printf("JESD204B_Lane0_CTRL_TX_ILA_LID\n\r");
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_Lane0_CTRL_TX_ILA_LID,0x00000000);
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_Lane0_CTRL_TX_ILA_LID,0x00000000);
    printf("JESD204B_Lane0_CTRL_TX_ILA_LID success\n\r");
    usleep(1000);
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_RESET,0x00000001);
    Xil_In32(XPAR_JESD204C_0_BASEADDR+JESD204C_RESET,0x00000000);
    //等待IP就绪
	while((Xil_Out32(XPAR_JESD204C_0_BASEADDR+JESD204C_RESET) & 0x00000001) == 0x00000001){
        usleep(5000);
    }

	while(((Xil_Out32(XPAR_JESD204_PHY_0_BASEADDR+0x80)) & 0x0000000F) != 0x00000000){
        usleep(5000);
    }
}

static void jesd204cInit(void)
{
	//初始化JESD204c IP
	Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_8B10B_CFG,0x03021F03);//F:4; K:32
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_TX_ILA_CFG0,0x00);
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_SUB_CLASS,0x00000001);
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_TEST_MODE,0x00000000);
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_LANE_ENA,0x00000001);//L:1
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_TX_ILA_CFG1,0x000F0F01);//NP:16; N:16; M:2
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_TX_ILA_CFG2,0x00000000);
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_CTRL_SYSREF,0x00000002);
    printf("JESD204C_Lane1_CTRL_TX_ILA_LID\n\r");
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_Lane0_CTRL_TX_ILA_LID,0x00000000);
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_Lane0_CTRL_TX_ILA_LID,0x00000000);
    printf("JESD204C_Lane1_CTRL_TX_ILA_LID success\n\r");
    usleep(1000);
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_RESET,0x00000001);
    Xil_In32(XPAR_JESD204C_1_BASEADDR+JESD204C_RESET,0x00000000);
    //等待IP就绪
	while((Xil_Out32(XPAR_JESD204C_1_BASEADDR+JESD204C_RESET) & 0x00000001) == 0x00000001){
        usleep(5000);
    }

	while(((Xil_Out32(XPAR_JESD204_PHY_1_BASEADDR+0x80)) & 0x0000000F) != 0x00000000){
        usleep(5000);
    }
}

bool ad9171Config(void)
{
	jesd204bInit();
	jesd204cInit();
	//AD9171复位和通道使能
	setGpioValue(Conf::currentConf()->mGpioConf.uAd9171nRST,0x00);
    usleep(5000);
	setGpioValue(Conf::currentConf()->mGpioConf.uAd9171nRST,0x01);
	setGpioValue(Conf::currentConf()->mGpioConf.uAd9171TxEn0,0x01);
	setGpioValue(Conf::currentConf()->mGpioConf.uAd9171TxEn1,0x01);//TODO:2024-11-27,新增一个通道 0 -》1
    return ad9171RegInit();
}

